import sys;
# from GraphAbstract.ActionAbstract import ActionController;
from GraphAbstract.EdgeAbstract import EdgeController;
from GraphAbstract.NodeAbstract import NodeController;
from GraphAbstract.NodeAbstract.NodeView import NodeView;
from GraphSettings.GraphFeatures.AnimationGraph import AnimationGraph;
from GraphSettings.GraphFeatures.LayoutGraph import LayoutGraph;
# from GraphSettings.GraphFeatures.Token import Token;
from PyQt4 import QtCore;

class GraphSceneView(object):
    animType = QtCore.QEasingCurve;
    
    def __init__(self, objGraph):
        self.graphModel = objGraph.graphModel;
        self.objGraph = objGraph;
#         self.createTokenSymbol();
        self.animGraph = AnimationGraph();
        self.bEdgesVisible, self.bNodesMovable = True, True;
        self.bNodesSelectable, self.bShowAllCtrlPts = True, False;
        self.bShowSelCtrlPts = False;

    def setGraphStyle(self, nStyle):
        self.setNodesStyle(nStyle);
        self.setEdgeStyle(nStyle);
    
    def setNodesStyle(self, nStyle):
        for node in self.objGraph.nodes:
            node.nodeView.setNodeStyle(nStyle);
    
    def setEdgesStyle(self, nStyle):
        for edge in self.objGraph.edges:
            edge.setEdgeStyle(nStyle);
            
    def applyGraphLayout(self, layoutType=0):
        layoutGraph = LayoutGraph(self.objGraph.nodes);
        if layoutType==0:
            tGrid = [[1,0,0,0,1],
                     [0,1,0,1,0],
                     [0,0,1,0,0],
                     [0,1,0,1,0],
                     [1,0,0,0,1]];
            layoutGraph.setGridLayout(tGrid, -350, -350, 150, 150);
        elif layoutType==1:
            layoutGraph.setFlowLayout(4, 3, -197, -100, 120, 200);
        elif layoutType==2:
            layoutGraph.setCircleLayout(-50, -50, 300, 300, 0.7, 1);
        elif layoutType==3:
            aPoints = [];
            x, y = 100,100;
            aPoints.append(QtCore.QPointF(250-x,100-y)*5);
            aPoints.append(QtCore.QPointF(150-x,150-y)*5);
            aPoints.append(QtCore.QPointF(90-x,150-y)*5);
            aPoints.append(QtCore.QPointF(-10-x,100-y)*5);
            aPoints.append(QtCore.QPointF(150-x,50-y)*5);
            layoutGraph.setCurveLayout(aPoints, 0, 1);
        self.animGraph.animateNodesPos(self.objGraph, self.objGraph.nodes, 
                                       layoutGraph.aNodesPos, 
                                       800, self.animType.InElastic);
                                       
    def applyGraphVizLayout(self, sType, pX, pY, sizeX, sizeY):
        layoutGraph = LayoutGraph(self.objGraph.nodes);
        g = self.objGraph.graphVizNodes;
        layoutGraph.setGraphVizLayout(g, sType, pX, pY, sizeX, sizeY);
        self.animGraph.animateNodesPos(self.objGraph, self.objGraph.nodes, 
                                       layoutGraph.aNodesPos, 
                                       800, self.animType.InElastic);
                                                                         
    def applyFlowLayout(self, pX, pY, rows, cols, spcX, spcY):
        layoutGraph = LayoutGraph(self.objGraph.nodes);
        layoutGraph.setFlowLayout(rows, cols, pX, pY, spcX, spcY);
        self.animGraph.animateNodesPos(self.objGraph, self.objGraph.nodes, 
                                       layoutGraph.aNodesPos, 
                                       800, self.animType.InElastic);
                                       
    def applyCircleLayout(self, pX, pY, width, height, init, end):
        layoutGraph = LayoutGraph(self.objGraph.nodes);
        layoutGraph.setCircleLayout(pX, pY, width, height, init, end);
        self.animGraph.animateNodesPos(self.objGraph, self.objGraph.nodes, 
                                       layoutGraph.aNodesPos, 
                                       800, self.animType.InElastic);
                                       
    def applyCurveLayout(self, aPoints, init, end, k):
        layoutGraph = LayoutGraph(self.objGraph.nodes);
        layoutGraph.setCurveLayout(aPoints, init, end, k);
        self.animGraph.animateNodesPos(self.objGraph, self.objGraph.nodes, 
                                       layoutGraph.aNodesPos, 
                                       800, self.animType.InElastic);
                                       
    def applyGridLayout(self, tGrid, pX, pY, spaceX, spaceY):
        layoutGraph = LayoutGraph(self.objGraph.nodes);
        layoutGraph.setGridLayout(tGrid, pX, pY, spaceX, spaceY);
        self.animGraph.animateNodesPos(self.objGraph, self.objGraph.nodes, 
                                       layoutGraph.aNodesPos, 
                                       800, self.animType.InElastic);
                                       
    def alignNodesLeft(self):
        nodes = self.objGraph.getSelectedItems(NodeController);
        if len(nodes) == 0: return;
        minX = sys.maxsize;
        aPoints = [];
        for node in nodes:
            if node.pos().x() < minX:
                minX = node.pos().x();
        for node in nodes:
            aPoints.append(QtCore.QPointF(minX, node.pos().y()));
        self.animGraph.animateNodesPos(self.objGraph, nodes, aPoints, 
                                       800, self.animType.InElastic);
        
    def alignNodesRight(self):
        nodes = self.objGraph.getSelectedItems(NodeController);
        if len(nodes) == 0: return;
        maxX = -sys.maxsize;
        aPoints = [];
        for node in nodes:
            if node.pos().x() > maxX:
                maxX = node.pos().x();
        for node in nodes:
            aPoints.append(QtCore.QPointF(maxX, node.pos().y()));
        self.animGraph.animateNodesPos(self.objGraph, nodes, aPoints, 
                                       800, self.animType.InElastic);
    
    def alignNodesCenterH(self):
        nodes = self.objGraph.getSelectedItems(NodeController);
        if len(nodes) == 0: return;
        minX = sys.maxsize;
        maxX = -sys.maxsize;
        aPoints = [];
        for node in nodes:
            if node.pos().x() > maxX:
                maxX = node.pos().x();
            if node.pos().x() < minX:
                minX = node.pos().x();
        if minX < 0:
            centerH = (maxX + -1*minX)/2.0;
            centerH += minX;
        else:
            centerH = (maxX - minX)/2.0;
        for node in nodes:
            aPoints.append(QtCore.QPointF(centerH, node.pos().y()));
        self.animGraph.animateNodesPos(self.objGraph, nodes, aPoints, 
                                       800, self.animType.InElastic);
    
    def alignNodesCenterV(self):
        nodes = self.objGraph.getSelectedItems(NodeController);
        if len(nodes) == 0: return;
        minY = sys.maxsize;
        maxY = -sys.maxsize;
        aPoints = [];
        for node in nodes:
            if node.pos().y() > maxY:
                maxY = node.pos().y();
            if node.pos().y() < minY:
                minY = node.pos().y();  
        if minY < 0:
            centerV = (maxY + -1*minY)/2.0;
            centerV += minY;
        else:              
            centerV = (maxY - minY)/2.0;
        for node in nodes:
            aPoints.append(QtCore.QPointF(node.pos().x(), centerV));
        self.animGraph.animateNodesPos(self.objGraph, nodes, aPoints, 
                                       800, self.animType.InElastic);
    
    def alignNodesTop(self):
        nodes = self.objGraph.getSelectedItems(NodeController);
        if len(nodes) == 0: return;
        minY = sys.maxsize;
        aPoints = [];
        for node in nodes:
            if node.pos().y() < minY:
                minY = node.pos().y();
        for node in nodes:
            aPoints.append(QtCore.QPointF(node.pos().x(), minY));
        self.animGraph.animateNodesPos(self.objGraph, nodes, aPoints, 
                                       800, self.animType.InElastic);
    
    def alignNodesBottom(self):
        nodes = self.objGraph.getSelectedItems(NodeController);
        if len(nodes) == 0: return;
        maxY = -sys.maxsize;
        aPoints = [];
        for node in nodes:
            if node.pos().y() > maxY:
                maxY = node.pos().y();
        for node in nodes:
            aPoints.append(QtCore.QPointF(node.pos().x(), maxY));
        self.animGraph.animateNodesPos(self.objGraph, nodes, aPoints, 
                                       800, self.animType.InElastic);
                
    def animTrans(self, iFrom, iAct, iTo, nDuration, animType, bReverse=False):
        edge = self.objGraph.getEdge(iFrom, iAct, iTo);
        if edge==None: return;
        self.token.setVisible(True);
        qPath = edge.edgeView.getSpline(False);
        self.animGraph.animTransition(self.token, qPath, nDuration, 
                                      animType, True, bReverse);
                                                  
#     def createTokenSymbol(self):
#         self.token = Token(QtCore.QPointF(0,0));
#         self.objGraph.addItem(self.token);
#         self.token.setVisible(False);
        
    def setEdgesVisible(self, bVisible=False):
        self.bEdgesVisible = bVisible;            
        for gNode in self.objGraph.nodes:
            for gAct in gNode.actions:
                gAct.actView.setShowOutEdges(bVisible);
                
    def showMaxProbEdges(self, bShow=False):
        for i in range(len(self.objGraph.nodes)):
            for j in range(len(self.objGraph.nodes)):
                gMaxEdge = None;
                nMax = -sys.maxsize;
                for gAct in self.objGraph.nodes[i].actions:
                    for gOutEdge in gAct.outEdges:
                        if gOutEdge.objTo.nodeModel.getStateId()==j+1:
                            nT = gOutEdge.edgeModel.getTransitionValue();
                            if nT > nMax:
                                nMax = nT;
                                gMaxEdge = gOutEdge;
                if gMaxEdge != None:
                    gMaxEdge.edgeView.setMaxEdge(bShow);
                    gMaxEdge.edgeView.updateEdgePathItem();
        self.objGraph.updateScene();                    
    
    def showAllCtrlPts(self, bVisible=False):
        self.bShowAllCtrlPts = bVisible;
        for gEdge in self.objGraph.edges:
            gEdge.edgeView.showCtrlPts(bVisible);
            
    def showSelCtrlPts(self, bVisible=False):
        self.bShowSelCtrlPts = bVisible;
        selectedEdges = self.objGraph.getSelectedItems(EdgeController);
        for gEdge in selectedEdges:
            gEdge.edgeView.showCtrlPts(bVisible);
            
    def setNodesMovable(self, bMovable=True):
        for node in self.objGraph.nodes:
            node.nodeView.setMovable(bMovable);
            
    def setNodesSelectable(self, bSelectable=True):
        for node in self.objGraph.nodes:
            node.nodeView.setSelectable(bSelectable);
            
    def selectEdges(self, bSelected=False, edges=[]):
        if len(edges)==0: edges = self.objGraph.edges;
        for edge in edges:
            edge.setSelected(bSelected);
            
    def selectNodes(self, bSelected=False, nodes=[]):
        if len(nodes)==0: nodes = self.objGraph.nodes;
        for node in nodes:
            node.setSelected(bSelected);
                
    def setEdgesZVal(self, zVal):
        edges = self.objGraph.edges;
        for edge in edges:
            edge.setZValue(zVal);
            
    def selectGraph(self, bSelected=False):
        self.selectEdges(bSelected);
        self.selectNodes(bSelected);
        self.selectActions(bSelected);
            
    def setNodes_StyleInfo(self, nStyleInfo):
        for node in self.objGraph.nodes:
            node.nodeView.setStyleInfo(nStyleInfo);
            
    def setEdges_StyleInfo(self, nStyleInfo):
        for edge in self.objGraph.edges:
            edge.edgeView.setStyleInfo(nStyleInfo);
            
    def setNodes_StyleStatus(self, nStyleStatus):
        for node in self.objGraph.getSelectedItems(NodeController):
            node.nodeView.setStyleStatus(nStyleStatus);
            
    def setNodes_CurrentStyle(self, nCurrentFrm):
        nNormal = NodeView.StatusStyle.normal;
        nCurrent = NodeView.StatusStyle.current;
        for node in self.objGraph.nodes:
            nInit = node.nodeModel.StartFrm;
            nEnd = node.nodeModel.EndFrm;
            if (nCurrentFrm>nInit and nCurrentFrm<=nEnd) or \
            (nCurrentFrm==0 and nInit==0):
                node.nodeView.setStyleStatus(nCurrent);
            else:
                node.nodeView.setStyleStatus(nNormal);
                
    def setNodes_Selected(self, aGrpIds, bSelected):
        for nId in aGrpIds:
            for node in self.objGraph.nodes:
                if node.nodeModel.GroupId==nId:
                    node.setSelected(bSelected);
    
    def setNodes_NormalStyle(self):
        nNormal = NodeView.StatusStyle.normal;
        for node in self.objGraph.nodes:
            node.nodeView.setStyleStatus(nNormal);                       
            
    def setNodes_All_StyleStatus(self, nStyleStatus):
        for node in self.objGraph.nodes:
            node.nodeView.setStyleStatus(nStyleStatus);

    def setNode_StyleStatus(self, iNodeId, nStyleStatus):
        node = self.objGraph.getNode(iNodeId);
        if node==None: return;
        node.nodeModel.setStateType(nStyleStatus);
            
    def setNodes_BkgColorType(self, nType, nMaxVal=1, nMinVal=0, nStDim=0):
        nMax = nMaxVal - nMinVal;
        nMax = 1 if nMax < 1 else nMax;
        for node in self.objGraph.nodes:
            node.nodeView.setBkgColor_ByVal(nType, nMax, nMinVal, nStDim);
            
    def setNodes_Theme(self, nTheme):
        if nTheme==0: #Generic
            for node in self.objGraph.nodes:
                node.nodeView.bHideWalls = True;
                node.nodeView.updateStWalls();
        elif nTheme==1: #Maze
            for node in self.objGraph.nodes:
                node.nodeView.bHideWalls = False;
                node.nodeView.updateStWalls();
            
    def setEdges_LineType(self, nType):
        for edge in self.objGraph.edges:
            edge.edgeView.setLineType(nType);
            
    def setNodes_StateShape(self, kCorners):
        for node in self.objGraph.nodes:
            node.nodeView.setStateShape(kCorners);

            
            